#include <crypto/ciphermanager.h>

#include <utility>
namespace crypto {
cipherManager::cipherManager(utils::CipherAlgorithm algorithm, Botan::SymmetricKey key, const std::filesystem::path &fileNameIV) : algos(algorithm), key(std::move(key)) {
	cipher = std::make_shared<Cipher>();
	std::size_t ivSize = algos == utils::CipherAlgorithm::Magma_CBC ? 8 : 16;
	cipher->generateIvWithSaving(ivSize);

	auto str = fileNameIV.string();
	path = Botan::secure_vector<uint8_t>(str.begin(), str.end());
}

cipherManager::cipherManager(utils::CipherAlgorithm algorithm, Botan::SymmetricKey key, const Botan::secure_vector<uint8_t>& data) : algos(algorithm), key(std::move(key))
{
	cipher = std::make_shared<Cipher>();
	cipher->chooseCipher(algorithm, Botan::Cipher_Dir::Decryption);
	cipher->setIV(data);
}

cipherManager::~cipherManager() = default;

void cipherManager::setPath(const std::filesystem::path &fileNameIV) {
	auto str = fileNameIV.string();
	path = Botan::secure_vector<uint8_t>(str.begin(), str.end());
}

void cipherManager::setPath(const Botan::secure_vector<uint8_t>& fileNameIV) {
	path = fileNameIV;
}

Botan::InitializationVector cipherManager::generateIV() {
	std::size_t ivSize = algos == utils::CipherAlgorithm::Magma_CBC ? 8 : 16;
	auto res = cipher->generateIV(ivSize);
	return res;
}


Botan::secure_vector<uint8_t> cipherManager::encrypt(const Botan::secure_vector<uint8_t> &plaintext, bool saveIV) {
	// Выбор алгоритма шифрования
	cipher->chooseCipher(algos, Botan::Cipher_Dir::Encryption);

	// Генерация нового IV и сохранение его, если необходимо
	if (saveIV) {
		std::size_t ivSize = algos == utils::CipherAlgorithm::Magma_CBC ? 8 : 16;
		cipher->generateIvWithSaving(ivSize);
	}


	auto encryptedText = cipher->encrypt(key, plaintext);


	if (saveIV) {
		cipher->saveIVInByteArray(encryptedText);
	}

	return encryptedText;
}

Botan::secure_vector<uint8_t> cipherManager::decrypt(const Botan::secure_vector<uint8_t> &ciphertext, bool loadIV) {
	cipher->chooseCipher(algos, Botan::Cipher_Dir::Decryption);
	std::size_t ivSize = algos == utils::CipherAlgorithm::Magma_CBC ? 8 : 16;
	if (loadIV) {
		// Загрузка IV из зашифрованных данных
		Botan::secure_vector<uint8_t> ivData(ivSize);
		std::copy(ciphertext.begin(), ciphertext.begin() + ivSize, ivData.begin());
		cipher->setIV(ivData);
	}

	size_t offset = loadIV ? ivSize : 0;
	auto dataToDecrypt = Botan::secure_vector<uint8_t>(ciphertext.begin() + offset, ciphertext.end());
	auto decryptedText = cipher->decrypt(key, dataToDecrypt);
	return decryptedText;
}

Botan::secure_vector<uint8_t> cipherManager::updateDecryption(const Botan::InitializationVector &newIV, const Botan::secure_vector<uint8_t> &plaintext) {
	auto res = cipher->updateEncryption(key, newIV, plaintext, algos);
	return res;
}

std::shared_ptr<Cipher> cipherManager::getCipher() {return cipher;}
}

